use std::sync::{
    mpsc::{channel, Receiver, Sender},
    Arc,
};

use egui::{ahash::HashMap, Align2, Color32, Margin, ScrollArea, Sense, Stroke};
use thunderdome::Index;
use QcCore::{ecs::component::Component, scene_system::scene::Scene};
use QcScript::{core::JsComponentData, serde_v8, v8};
use QcUI::{
    component::{Button, Canvas, FlexDirection, Label, Panel, ToUi, UiNodeTrait, Widget},
    core::context::UiContext,
};

use crate::{
    components::dock::DockView,
    core::{
        component_data::ComponentData,
        context::Context,
        message::{ComponentType, EditorMessage, ObjectType},
    },
    inspector::{ComponentStateList, InspectorContext, InspectorTrait},
};

use super::UiPanelMessage;

#[derive(Debug)]
pub enum AttrPanelMessage {
    RebuildComponentList,
    RefreshComponentState,
}

#[derive(Debug)]
pub struct AttrPanelState {
    add_component_window: bool,
    components: Vec<ComponentData>,
    target: Index, // 临时缓存选择的对象
}

#[derive(Debug)]
pub struct AttrPanel {
    context: Arc<Context>,
    state: AttrPanelState,
    editor_sender: Sender<EditorMessage>,
    inspector_state: ComponentStateList,
    pub sender: Sender<AttrPanelMessage>,
    receiver: Receiver<AttrPanelMessage>,
}

impl DockView for AttrPanel {
    fn render(&mut self, ctx: &mut UiContext, show_tab: bool) {
        let actions = self.context.editor_actions.clone();

        if let (obj_type, Some(current)) = actions.current() {
            {
                let context = self.context.clone();
                let mut scene_manager = context.scene_manager.try_write().unwrap();
                let scene = scene_manager.get_current_scene_mut().unwrap();

                match obj_type {
                    ObjectType::GameObject => {
                        self.show_game_object_panel(ctx, scene, current);
                    }
                    ObjectType::UiObject => {
                        if let Some(index) = scene.get_main_canvas() {
                            self.show_ui_node_panel(ctx, scene, index, current);
                        } else {
                            ctx.ui.label("找不到 Canvas 组件");
                        }
                    }
                }
            }

            if self.state.add_component_window && obj_type == ObjectType::GameObject {
                self.show_component_window(ctx);
            }

            ctx.ui.input(|input| {
                let message_center = self.context.message_center.try_read().unwrap();

                if let Some(pos) = input.pointer.interact_pos() {
                    if input.pointer.primary_pressed() && ctx.ui.clip_rect().contains(pos) {
                        message_center.send_to_ui_panel(UiPanelMessage::IsCapture(false));
                    }
                }

                if input.pointer.primary_released() {
                    message_center.send_to_ui_panel(UiPanelMessage::IsCapture(true));
                }
            })
        }
    }
}

impl AttrPanel {
    pub fn new(context: Arc<Context>, editor_sender: Sender<EditorMessage>) -> Self {
        let resource_manager = context.resource_manager.clone();

        let code = resource_manager.get("./dist/quincy.umd.cjs");

        let mut components = if let Some(code) = code {
            let data = String::from_utf8(code.file.data.to_vec())
                .expect(&format!("无法读取构建后的 JavaScript 文件"));

            let mut js_runtime_manager = context.js_runtime_manager.try_write().unwrap();
            js_runtime_manager
                .execute_script_static("qc", data.leak())
                .unwrap();

            let js_runtime = js_runtime_manager.main_realm();
            let isolate = js_runtime_manager.v8_isolate();

            let mut scope = js_runtime.handle_scope(isolate);
            let context = scope.get_current_context();
            let globalThis = context.global(&mut scope);
            let key = v8::String::new(&mut scope, "__Components__").unwrap();
            // 获取全部组件
            let components = globalThis
                .get(&mut scope, key.into())
                .expect("无法获取全部组件");

            let components: Vec<JsComponentData> =
                serde_v8::from_v8(&mut scope, components).expect("无法获取全部组件");

            components.iter().map(|comp| comp.clone().into()).collect()
        } else {
            vec![]
        };

        components.append(
            &mut ComponentType::list()
                .iter()
                .map(|comp| (*comp).into())
                .collect(),
        );

        let state = AttrPanelState {
            add_component_window: false,
            components,
            target: Index::DANGLING,
        };
        let (sender, receiver) = channel();

        let inspector_state = ComponentStateList::new(context.clone());
        Self {
            context,
            state,
            editor_sender,
            inspector_state,
            sender,
            receiver,
        }
    }

    pub fn show_component_window(&mut self, ctx: &mut UiContext) {
        egui::Frame::none()
            .outer_margin(Margin::same(10.))
            .show(ctx.ui, |ui| {
                ScrollArea::vertical().auto_shrink(false).show(ui, |ui| {
                    ui.with_layout(
                        egui::Layout::top_down(egui::Align::LEFT).with_cross_justify(true),
                        |ui| {
                            let mut obj = None;
                            egui::ScrollArea::new([false, true]).show(ui, |ui| {
                                for comp in &self.state.components {
                                    let text = comp.get_name();
                                    egui::Frame::none()
                                        .inner_margin(Margin::symmetric(10., 0.))
                                        .fill(egui::Color32::BLACK)
                                        .show(ui, |ui| {
                                            let button = egui::Button::new(text)
                                                .min_size(egui::Vec2::new(
                                                    ui.available_width(),
                                                    30.,
                                                ))
                                                .fill(egui::Color32::BLACK)
                                                .stroke(Stroke::NONE);
                                            if ui.add(button).clicked() {
                                                self.state.add_component_window = false;
                                                obj = Some(comp)
                                            }
                                        });
                                }
                            });

                            if let Some(comp) = obj {
                                self.editor_sender
                                    .send(EditorMessage::AddComponent(comp.clone()))
                                    .unwrap();
                            }
                        },
                    );
                });
            });
    }

    pub fn show_game_object_panel(
        &mut self,
        ctx: &mut UiContext,
        scene: &mut Scene,
        current: Index,
    ) {
        let obj = &mut scene[current];

        ctx.ui.horizontal(|ui| {
            ui.checkbox(&mut obj.active, "");
            ui.add(egui::TextEdit::singleline(&mut obj.name));
        });

        let mut inspector_ctx = InspectorContext::new(ctx.ui, &self.editor_sender);
        for (_, comp) in obj.iter_mut() {
            let state = self.inspector_state.get_state_mut(comp.into());
            comp.inspector(&mut inspector_ctx, state);
        }

        ctx.ui.vertical_centered(|ui| {
            ui.add_space(10.);
            let button = egui::Button::new("添加组件")
                .min_size(egui::Vec2::new(100., 30.))
                .stroke(Stroke::NONE);
            if ui.add(button).clicked() {
                self.state.add_component_window = !self.state.add_component_window;
            }
        });
    }

    pub fn show_ui_node_panel(
        &mut self,
        ctx: &mut UiContext,
        scene: &mut Scene,
        canvas: Index,
        current: Index,
    ) {
        let scene_ptr = scene as *mut _;
        if let Some(canvas) = scene[canvas].getComponentMut::<Canvas>() {
            let widget = canvas[current].get_widget_mut();

            ctx.ui.horizontal(|ui| {
                ui.checkbox(&mut widget.active, "");
                ui.add(egui::TextEdit::singleline(&mut widget.name));
            });

            if self.state.target != current {
                self.inspector_state.refresh();
                self.state.target = current;
            }

            let mut inspector_ctx = InspectorContext::new(ctx.ui, &self.editor_sender);

            let state = self.inspector_state.get_state_mut(ComponentType::Widget);
            widget.inspector(&mut inspector_ctx, state);

            let canvas_ptr = canvas as *mut _;

            let mut inspector_ctx = inspector_ctx
                .with_canvas_ptr(canvas_ptr)
                .with_scene_ptr(scene_ptr);
            let ui_node = &canvas[current];
            let state = self.inspector_state.get_state_mut(ui_node.into());
            canvas[current].inspector(&mut inspector_ctx, state)
        }
    }
}
